use anyhow::{anyhow, Context, Result};
use time::{Date, Duration, Month, OffsetDateTime, format_description};

/// 字符串解析成日期
pub fn parse(input: &str, fmt: &str) -> Result<OffsetDateTime> {
    let format = format_description::parse(fmt)?;
    OffsetDateTime::parse(input, &format).with_context(|| anyhow!("日期错误"))
}

/// 日期解析成字符串
pub fn format(date_time: &OffsetDateTime, fmt: &str) -> Result<String> {
    let format = format_description::parse(fmt)?;
    date_time
        .format(&format)
        .with_context(|| anyhow!("日期错误"))
}

/// 获取某天的开始时间
pub fn begin_of_day(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    Ok(date
        .with_hms(0, 0, 0)?
        .assume_offset(offset))
}

/// 获取某天的结束时间
pub fn end_of_day(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    Ok(date
        .with_hms(23, 59, 59)?
        .assume_offset(offset))
}

/// 获取某月的开始时间
pub fn begin_of_month(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    let year = date.year();
    let month = date.month();
    Ok(Date::from_calendar_date(year, month, 1)?
        .with_hms(0, 0, 0)?
        .assume_offset(offset))
}

/// 获取某月的结束时间
pub fn end_of_month(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    let year = date.year();
    let month = date.month();
    let days = days_in_month(year, month)?;
    Ok(Date::from_calendar_date(year, month, days)?
        .with_hms(23, 59, 59)?
        .assume_offset(offset))
}

/// 获取某季度的开始时间
pub fn begin_of_quarter(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    let year = date.year();
    let quarter = quarter(&date);
    let quarter_end_month = quarter * 3;
    let quarter_start_month = quarter_end_month - 2;
    let month = Month::try_from(quarter_start_month)?;
    Ok(Date::from_calendar_date(year, month, 1)?
        .with_hms(0, 0, 0)?
        .assume_offset(offset))
}

/// 获取某季度的结束时间
pub fn end_of_quarter(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    let year = date.year();
    let quarter = quarter(&date);
    let quarter_end_month = quarter * 3;
    let month = Month::try_from(quarter_end_month)?;
    let days = days_in_month(year, month)?;
    Ok(Date::from_calendar_date(year, month, days)?
        .with_hms(23, 59, 59)?
        .assume_offset(offset))
}

/// 获取某年的开始时间
pub fn begin_of_year(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    let year = date.year();
    Ok(Date::from_calendar_date(year, Month::January, 1)?
        .with_hms(0, 0, 0)?
        .assume_offset(offset))
}

/// 获取某年的结束时间
pub fn end_of_year(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    let year = date.year();
    Ok(Date::from_calendar_date(year, Month::December, 31)?
        .with_hms(23, 59, 59)?
        .assume_offset(offset))
}

/// 获取某周的开始时间
pub fn begin_of_week(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    let weekday = date.weekday();
    let number_from_monday = weekday.number_from_monday();
    let date_naive = date
        .checked_sub(Duration::days(number_from_monday as i64)).unwrap();
    Ok(date_naive
        .with_hms(0, 0, 0)?
        .assume_offset(offset))
}

/// 获取某周的结束时间
pub fn end_of_week(date_time: &OffsetDateTime) -> Result<OffsetDateTime> {
    let offset = date_time.offset();
    let date = date_time.date();
    let weekday = date.weekday();
    let number_from_sunday = weekday.number_from_sunday();
    let date = date
        .checked_add(Duration::days(number_from_sunday as i64)).unwrap();
    Ok(date
        .with_hms(23, 59, 59)?
        .assume_offset(offset))
}

/// 获取某年的某个月的天数
pub fn days_in_month(year: i32, month: Month) -> Result<u8> {
    // 创建下个月的第一天，然后减去1天得到当前月的最后一天
    let next_month = if month == Month::December {
        Date::from_calendar_date(year + 1, Month::January, 1)?
    } else {
        Date::from_calendar_date(year, month.next(), 1)?
    };

    let last_day_of_month = next_month
        .checked_sub(Duration::DAY).unwrap();
    Ok(last_day_of_month.day())
}

/// 获取季度
pub fn quarter(date: &Date) -> u8 {
    match date.month() {
        Month::January | Month::February | Month::March => 1,
        Month::April | Month::May | Month::June => 2,
        Month::July | Month::August | Month::September => 3,
        Month::October | Month::November | Month::December => 4,
    }
}
